'''
Created on 08/ott/2009

@author: syn
'''
import datetime
import gtk
import hashlib

from ui.GladeBase import GladeBase
from utils import EMAIL_PATTERN, logger

from ui import *
from soap import *

NO_ENTITY = -1
TYPE_ADMIN = 'admin'
TYPE_AUTHOR = 'author'
TYPE_BOOKSHOP = 'bookshop'
TYPES_LIST = (TYPE_ADMIN, TYPE_AUTHOR, TYPE_BOOKSHOP)

class ManageUser(GladeBase):
    
    def __init__(self, query=None, top_component=None):
        GladeBase.__init__(self, 'manage_user_frame', top_component)
        
        # Setting up users treeview
        cell = gtk.CellRendererText()
        tvc = gtk.TreeViewColumn('Users')
        tvc.pack_start(cell, True)
        tvc.add_attribute(cell, 'text', 1)
        self.user_treeview.append_column(tvc)
        
        # loading list model
        self.user_list = gtk.ListStore(int, str, object)
        self.user_list.set_sort_column_id(1, gtk.SORT_ASCENDING)
        
        # call soap web service to retrieve user list
        try:
            users = client.get_users()
            for user in users:
                self._append_user(user)
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
            
        self.user_treeview.set_model(self.user_list)
        self.user_frame_hpaned.set_position(400)
        
        # loading types list
        self.type_list = gtk.ListStore(str)
        for type in TYPES_LIST:
            self.type_list.append((type,))
        self.type_combobox.set_model(self.type_list)
        
        self._init_gui_components()
        self.password_changed = False
        self.entity_key = NO_ENTITY
    
    def _append_user(self, user):
        """
        Add a user to the list
        """
        self.user_list.append([user.id, user.username, user])
        
    def _update_user(self, row, user):
        """
        Update a user row in model with new value
        """
        self.user_list.set(row.iter, 1, user.username, 2, user)
    
    def _init_gui_components(self):
        """
        Intialize gui components as needed. This is useful in the contructor or 
        binded with particular actions (for instance, a "clear" button, or "new" button) 
        """
        self.username_entry.set_text("")
        self.password_entry.set_text("")
        self.repassword_entry.set_text("")
        self.email_entry.set_text("")
        self.active_checkbutton.set_active(True)
        self.type_combobox.set_active(-1)
        self.subject_combobox.set_model()
        self.password_changed = False
        self.apply_button.set_sensitive(False)
    
    def _retrieve_components(self):
        """
        Retrieve all used gui components from builder. This method is called in the
        GladeBase constructor
        """
        self.get_from_builder('username_entry')
        self.get_from_builder('password_entry')
        self.get_from_builder('repassword_entry')
        self.get_from_builder('email_entry')
        self.get_from_builder('active_checkbutton')
        self.get_from_builder('type_combobox')
        self.get_from_builder('subject_combobox')
        self.get_from_builder('user_treeview')
        self.get_from_builder('apply_button')
        self.get_from_builder('user_frame_hpaned')
    
    def _load_authors_list(self):
        cr1, cr2 = gtk.CellRendererText(), gtk.CellRendererText()
        self.subject_combobox.clear()
        self.subject_combobox.pack_start(cr1, True)
        self.subject_combobox.add_attribute(cr1, 'text', 2)
        self.subject_combobox.pack_start(cr2, True)
        self.subject_combobox.add_attribute(cr2, 'text', 1)
        author_list = gtk.ListStore(int, str, str)
        try:
            authors = client.get_authors(None)
            for author in authors:
                author_list.append([author.id, author.name, author.surname])
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
        
        self.subject_combobox.set_model(author_list)
        
    def _load_bookshops_list(self):
        cr1 = gtk.CellRendererText()
        self.subject_combobox.clear()
        self.subject_combobox.pack_start(cr1, True)
        self.subject_combobox.set_attributes(cr1, text=1)
        bookshop_list = gtk.ListStore(int, str)
        try:
            bookshops = client.get_bookshops(None)
            for bookshop in bookshops:
                bookshop_list.append([bookshop.id, bookshop.company_name])
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
        
        self.subject_combobox.set_model(bookshop_list)
    
    def _load_admins_list(self):
        # TODO:
        pass
    
    def _has_valid_data(self):
        """
        Formal control for data in the input form.
        
        return: boolean. 'True' when data is valid
        """
        username = self.username_entry.get_text()
        password = self.password_entry.get_text()
        repassword = self.repassword_entry.get_text()
        email = self.email_entry.get_text()
        
        if not username:
            mandatory_data_error('Username', self.username_entry)
            return False
        
        # check if username exist
        if self.entity_key == NO_ENTITY and search(self.user_list, (1, username)):
            generic_data_error('Username exist', self.username_entry)
            return False
        
        if not email:
            mandatory_data_error('Email', self.email_entry)
            return False
        
        if not EMAIL_PATTERN.match(email):
            generic_data_error('Please insert a valid email address', self.email_entry)
            return False
        
        if self.entity_key == NO_ENTITY or self.password_changed: 
            if not password:
                mandatory_data_error('Password', self.password_entry)
                return False
            
            if password != repassword:
                generic_data_error("Password and re-password don't match", self.password_entry)
                return False
        
        if self.type_combobox.get_active() < 0:
            mandatory_data_error('Type', self.type_combobox)
            return False
        
        if self.subject_combobox.get_active() < 0:
            mandatory_data_error('Subject', self.subject_combobox)
            return False
        
        return True
    
    def _save_data(self):
        """
        Save changes to db. 
        
        return: 'True' if data have been successfully saved 
        """
        if not self._has_valid_data():
            return False
        
        if self.entity_key == NO_ENTITY:
            user = UserSoap()
        else:
            row = search(self.user_list, (0, self.entity_key))
            user = row[2]
        
        user.username = self.username_entry.get_text()
        password = self.password_entry.get_text()
        if password:
            user.password = hashlib.md5(password).hexdigest()
        user.email = self.email_entry.get_text()
        user.active = self.active_checkbutton.get_active()
        
        user.type = TYPES_LIST[self.type_combobox.get_active()]
        
        # retrieving id of the subject connected to this user
        model = self.subject_combobox.get_model()
        iter = self.subject_combobox.get_active_iter()
        user.subject = model.get_value(iter, 0)
        
        # save changes
        try:
            user.id = client.save_user(user)
            if not user.id > 0:
                raise Exception("Problem occurred on server during save")
            
            if self.entity_key == NO_ENTITY:
                self._append_user(user)
            else:
                # update row in user list
                row = search(self.user_list, (0, user.id))
                self._update_user(row, user)
            
            self.entity_key = user.id
            self.password_changed = False
            self.apply_button.set_sensitive(False)
            return True
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
            return False
    
    # Signals
    def on_user_changed(self, *args, **kwargs):
        self.apply_button.set_sensitive(True)
        if args[0] in (self.password_entry, self.repassword_entry):
            self.password_changed = True
    
    def on_type_combobox_changed(self, combobox, data=None):
        iter = combobox.get_active_iter()
        if not iter:
            return
        
        type = self.type_list.get_value(iter, 0)
        self.subject_combobox.set_model()
        if type == TYPE_AUTHOR:
            self._load_authors_list()
        elif type == TYPE_BOOKSHOP:
            self._load_bookshops_list()
        elif type == TYPE_ADMIN:
            self._load_admins_list()
        
        self.on_user_changed(combobox, data)
    
    def on_user_treeview_row_activated(self, treeview, path, view_column, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                    
        self._init_gui_components()
        
        user = self.user_list[path][2]
        self.entity_key = user.id
        
        self.username_entry.set_text(user.username)
        self.email_entry.set_text(user.email)
        self.active_checkbutton.set_active(user.active)
        
        type_index = TYPES_LIST.index(user.type)
        self.type_combobox.set_active(type_index)
        
        if type == TYPE_AUTHOR:
            self._load_authors_list()
        elif type == TYPE_BOOKSHOP:
            self._load_bookshops_list()
        elif type == TYPE_ADMIN:
            self._load_admins_list()
        
        # searching in subject list 
        model = self.subject_combobox.get_model()
        subject = search(model, (0, user.subject))
        self.subject_combobox.set_active_iter(subject.iter)
        
        self.apply_button.set_sensitive(False)
         
    def on_new_button_clicked(self, object, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                
        self._init_gui_components()
        self.user_treeview.get_selection().unselect_all()
        self.entity_key = NO_ENTITY

    def on_apply_button_clicked(self, object, data=None):
        self._save_data()
    
    def on_delete_button_clicked(self, object, data=None):
        (model, iter) = self.user_treeview.get_selection().get_selected()
        if not iter:
            return
            
        user = model.get_value(iter, 2)
        try:
            client.delete_user(user)
            model.remove(iter)
            
            self._init_gui_components()
            self.entity_key = NO_ENTITY
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
